/*
 * Copyright (C) 2018 Zhejiang xiaominfo Technology CO.,LTD.
 * All rights reserved.
 * Official Web Site: http://www.xiaominfo.com.
 * Developer Web Site: http://open.xiaominfo.com.
 */

package com.github.xiaoymin.map.ext;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.crypto.digest.MD5;
import com.github.xiaoymin.map.MapClientConfig;
import com.github.xiaoymin.map.common.MapClientConstants;
import com.github.xiaoymin.map.model.AmapKey;
import com.github.xiaoymin.map.model.MapLocation;
import com.github.xiaoymin.map.util.GsonUtils;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import org.apache.http.HttpRequest;
import org.apache.http.client.methods.HttpUriRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;


/**
 * @author <a href="mailto:xiaoymin@foxmail.com">xiaoymin@foxmail.com</a>
 * 2020/09/21 19:30
 * @since:map-client 1.0
 */
public abstract class AmapAbstractClient extends AbstractMapClient{

    private Logger logger= LoggerFactory.getLogger(AmapAbstractClient.class);
    /**
     * 根据开发配置构造MapClient
     * @param mapClientConfig 开发配置
     */
    protected AmapAbstractClient(MapClientConfig mapClientConfig) {
        super(mapClientConfig);
    }

    /**
     * 构造签名
     * https://lbs.amap.com/faq/quota-key/key/41181
     * @param param 请求参数
     * @param amapKey 开发配置
     * @return 签名字符串
     */
    protected String sign(Map<String,String> param, AmapKey amapKey){
        //判断是否需要签名
        if (amapKey.isSign()){
            StringBuilder signBuilder=new StringBuilder();
            if (CollectionUtil.isNotEmpty(param)){
                List<String> keyList=CollectionUtil.newArrayList(param.keySet().iterator());
                Collections.sort(keyList);
                int keyLength=keyList.size();
                for (int i=0;i<keyLength;i++){
                    if (i>0){
                        signBuilder.append("&");
                    }
                    signBuilder.append(keyList.get(i)).append("=").append(param.get(keyList.get(i)));
                }
            }
            String signBefore=signBuilder.toString()+amapKey.getSignKey();
            logger.info("签名前参数:{}",signBefore);
            String sign= MD5.create().digestHex(signBefore);
            logger.info("签名参数:{}",sign);
            return sign;
        }
        return null;
    }

    /**
     * 对于请求参数Map追加接口秘钥key
     * @param param
     * @param amapKey
     * @return
     */
    protected Map<String,String> appendKey(Map<String,String> param, AmapKey amapKey){
        param.put("key",amapKey.getKey());
        return param;
    }
    /**
     * 构造请求参数
     * @param params 参数列表
     * @param amapKey 开发配置
     * @return 请求参数
     */
    protected String parameter(Map<String,String> params,AmapKey amapKey){
        StringBuilder paramBuilder=new StringBuilder();
        if (CollectionUtil.isNotEmpty(params)){
            ConcurrentHashMap<String,String> newParams=MapUtil.newConcurrentHashMap(params);
            //判断是否需要签名
            if (amapKey.isSign()){
                String sign=sign(params,amapKey);
                newParams.put("sig",sign);
            }
            List<String> paramsArr=new ArrayList<>();
            for (Map.Entry<String,String> entry:newParams.entrySet()){
                paramsArr.add(entry.getKey()+"="+entry.getValue());
            }
            paramBuilder.append(CollectionUtil.join(paramsArr,"&"));
        }
        String parameter=paramBuilder.toString();
        if (StrUtil.isNotBlank(parameter)){
            logger.info("参数编码前:{}",parameter);
            parameter= URLUtil.encode(parameter);
        }
        logger.info("请求参数:{}",parameter);
        return parameter;
    }

    /**
     * 获取返回接口
     * @param httpUriRequest 请求request
     * @param clazz 反射类
     * @param <T> 泛型对象
     * @return optional对象
     */
    protected <T> Optional<T> response(HttpUriRequest httpUriRequest, Class<T> clazz){
        String content=execute(httpUriRequest);
        if (StrUtil.isNotBlank(content)){
            JsonElement jsonElement=jsonParser.parse(content);
            JsonObject jsonObject=jsonElement.getAsJsonObject();
            String status=jsonObject.get("status").getAsString();
            if (StrUtil.equals(status, MapClientConstants.AMAP_RESPONSE_SUCCESS)){
                return Optional.ofNullable(gson.fromJson(jsonObject.get("regeocode"),clazz));
            }
        }
        return Optional.empty();
    }

    /**
     * 高德地图的返回成功标志处理返回json
     * @param httpRequest 请求
     * @return 成功后的JsonObject对象
     */
    protected JsonObject responseSuccess(HttpUriRequest httpRequest){
        String content=execute(httpRequest);
        if (StrUtil.isNotBlank(content)) {
            JsonElement jsonElement = jsonParser.parse(content);
            if (jsonElement != null && jsonElement.isJsonObject() && jsonElement.getAsJsonObject() != null) {
                JsonObject jsonObject = jsonElement.getAsJsonObject();
                String status = GsonUtils.getString(jsonObject, "status");
                if (StrUtil.equals(status, MapClientConstants.AMAP_RESPONSE_SUCCESS)) {
                    //成功
                    return jsonObject;
                }else{
                    logger.error("高德地图请求接口失败,infocode:{},info:{}",GsonUtils.getString(jsonObject,"infocode"),GsonUtils.getString(jsonObject,"info"));
                }
            }
        }
        return null;
    }

}
